﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace LiBLaB.IImage
{
    public struct IPixel
    {
        public byte R, G, B;
        public IPixel(Color color)
        {
            R = color.R;
            G = color.G;
            B = color.B;
        }
    }

    public class IImage
    {
        Bitmap img;
        public IPixel[,] Pixels;
        public int Width;
        public int Height;
        
        public IImage(string file_path)
        {
            img = (Bitmap)Image.FromFile(file_path);
            Width = img.Width;
            Height = img.Height;
            m_BmpTo2D();
        }

        public IImage(Image normal_image)
        {
            img = (Bitmap)normal_image;
            Width = img.Width;
            Height = img.Height;
            m_BmpTo2D();
        }
        public IImage(int width, int height)
        {
            Width = width;
            Height = height;
            img = new Bitmap(Width, Height);
            m_BmpTo2D();
        }

        public static Image ImageFromStream(byte[] Bytes)
        {
            byte[] w = new byte[4];
            byte[] h = new byte[4];
            Array.Copy(Bytes, 0, w, 0, 4);
            Array.Copy(Bytes, 4, h, 0, 4);
            int Width = BitConverter.ToInt32(w,0);
            int Height = BitConverter.ToInt32(h, 0);
            Bitmap bmp = new Bitmap(Width, Height);

            BitmapData bData = bmp.LockBits(new Rectangle(new Point(), bmp.Size),
                ImageLockMode.WriteOnly,
                PixelFormat.Format24bppRgb);
            Marshal.Copy(Bytes, 8, bData.Scan0, Bytes.Length-8);
            bmp.UnlockBits(bData);
            return bmp;
        }

        public static byte[] StreamFromImage(Image image)
        {
            Bitmap img = (Bitmap)image;
            if (img.Width % 4 == 0)
                img = (Bitmap)m_CropImage(img, new Rectangle(0, 0, img.Width - (img.Width % 4), img.Height));
            //B,G,R
            BitmapData bData = img.LockBits(new Rectangle(new Point(), img.Size),
                ImageLockMode.ReadOnly,
                PixelFormat.Format24bppRgb);
            // number of bytes in the bitmap
            int byteCount = bData.Stride * img.Height;
            byte[] bmpBytes = new byte[byteCount+8];
            Array.Copy(BitConverter.GetBytes(img.Width),0,bmpBytes,0,4);
            Array.Copy(BitConverter.GetBytes(img.Height), 0, bmpBytes, 4, 4);
            // Copy the locked bytes from memory
            Marshal.Copy(bData.Scan0, bmpBytes, 8, byteCount);
            // don't forget to unlock the bitmap!!
            img.UnlockBits(bData);
            return bmpBytes;
        }

        public Image Bitmap
        {
            get { return m_2DToBmp(); }
        }

        unsafe void m_BmpTo2D()
        {
            if (img.Width % 4 == 0)
                img = (Bitmap)m_CropImage(img, new Rectangle(0, 0, img.Width - (img.Width % 4), img.Height));
            //B,G,R
            BitmapData bData = img.LockBits(new Rectangle(new Point(), img.Size),
                ImageLockMode.ReadOnly,
                PixelFormat.Format24bppRgb);
            // number of bytes in the bitmap
            int byteCount = bData.Stride * img.Height;
            byte[] bmpBytes = new byte[byteCount];

            // Copy the locked bytes from memory
            Marshal.Copy(bData.Scan0, bmpBytes, 0, byteCount);
            // don't forget to unlock the bitmap!!
            img.UnlockBits(bData);

            int index = 0;
            Pixels = new IPixel[img.Width, img.Height];

            for (int j = 0; j < img.Height; j++)
            {
                for (int i = 0; i < img.Width; i++)
                {
                    Pixels[i, j].R = bmpBytes[index++];
                    Pixels[i, j].G = bmpBytes[index++];
                    Pixels[i, j].B = bmpBytes[index++];
                }
            }
        }

        Image m_2DToBmp()
        {
            Bitmap bmp = new Bitmap(img.Width, img.Height);

            BitmapData bData = bmp.LockBits(new Rectangle(new Point(), bmp.Size),
                ImageLockMode.WriteOnly,
                PixelFormat.Format24bppRgb);
            // Copy the bytes to the bitmap object
            byte[] bmpBytes = new byte[img.Width * img.Height * 3];
            int index = 0;
            for (int j = 0; j < img.Height; j++)
            {
                for (int i = 0; i < img.Width; i++)
                {
                    bmpBytes[index++] = Pixels[i, j].R;
                    bmpBytes[index++] = Pixels[i, j].G;
                    bmpBytes[index++] = Pixels[i, j].B;
                }
            }
            Marshal.Copy(bmpBytes, 0, bData.Scan0, bmpBytes.Length);
            bmp.UnlockBits(bData);
            return bmp;
        }

        private static Image m_CropImage(Image img, Rectangle cropArea)
        {
            if (cropArea.X < 0)
                cropArea.X = 0;
            if (cropArea.Y < 0)
                cropArea.Y = 0;
            Size new_size = cropArea.Size;
            if (cropArea.X + cropArea.Width > img.Width)
                new_size.Width = cropArea.X + cropArea.Width;
            if (cropArea.Y + cropArea.Height > img.Height)
                new_size.Height = cropArea.Y + cropArea.Height;
            Bitmap new_bitmap = new Bitmap(new_size.Width + 1, new_size.Height + 1);
            Graphics.FromImage(new_bitmap).DrawImage(img, 0, 0);

            if (cropArea.Width != 0 && cropArea.Height != 0)
            {
                return new_bitmap.Clone(cropArea,
                img.PixelFormat);
            }
            return img;
        }

        private Image m_ResizeImage(Image imgToResize, Size size)
        {
            int sourceWidth = imgToResize.Width;
            int sourceHeight = imgToResize.Height;

            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)size.Width / (float)sourceWidth);
            nPercentH = ((float)size.Height / (float)sourceHeight);

            int destWidth = (int)(sourceWidth * nPercentW);
            int destHeight = (int)(sourceHeight * nPercentH);

            Bitmap b = new Bitmap(destWidth, destHeight);
            Graphics g = Graphics.FromImage((Image)b);
            g.InterpolationMode = InterpolationMode.HighQualityBilinear;
            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
            g.Dispose();
            return (Image)b;
        }
    }
}
